using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;

namespace OpenAI.Chat
{
    public sealed class Message
    {
        internal Message(Delta other) { CopyFrom(other); }

        public Message() { }

        [Obsolete("Use new constructor args")]
        public Message(Role role, string content, string name, Function function)
            : this(role, content, name)
        {
            Name = name;
            Function = function;
        }

        /// <summary>
        /// Creates a new message to insert into a chat conversation.
        /// </summary>
        /// <param name="role">
        /// The <see cref="OpenAI.Role"/> of the author of this message.
        /// </param>
        /// <param name="content">
        /// The contents of the message.
        /// </param>
        /// <param name="name"></param>
        public Message(Role role, IEnumerable<Content> content, string name = null)
        {
            Role = role;
            Content = content.ToList();
            Name = name;
        }

        /// <summary>
        /// Creates a new message to insert into a chat conversation.
        /// </summary>
        /// <param name="role">
        /// The <see cref="OpenAI.Role"/> of the author of this message.
        /// </param>
        /// <param name="content">
        /// The contents of the message.
        /// </param>
        /// <param name="name"></param>
        public Message(Role role, string content, string name = null)
        {
            Role = role;
            Content = content;
            Name = name;
        }

        /// <inheritdoc />
        public Message(Tool tool, string content)
            : this(Role.Tool, content, tool.Function.Name)
        {
            ToolCallId = tool.Id;
        }

        /// <summary>
        /// Creates a new message to insert into a chat conversation.
        /// </summary>
        /// <param name="tool">Tool used for message.</param>
        /// <param name="content">Tool function response.</param>
        public Message(Tool tool, IEnumerable<Content> content)
            : this(Role.Tool, content, tool.Function.Name)
        {
            ToolCallId = tool.Id;
        }

        /// <summary>
        /// The <see cref="OpenAI.Role"/> of the author of this message.
        /// </summary>
        
        [JsonProperty("role")]
        public Role Role { get; private set; }

        /// <summary>
        /// The contents of the message.
        /// </summary>
        
        [JsonProperty("content")]
        public dynamic Content { get; private set; }

        private List<Tool> toolCalls;

        /// <summary>
        /// The tool calls generated by the model, such as function calls.
        /// </summary>
        
        [JsonProperty("tool_calls")]
        public IReadOnlyList<Tool> ToolCalls
        {
            get { return toolCalls; }
            private set { toolCalls = value.ToList(); }
        }

        
        [JsonProperty("tool_call_id")]
        public string ToolCallId { get; private set; }

        /// <summary>
        /// The function that should be called, as generated by the model.
        /// </summary>
        
        [Obsolete("Replaced by ToolCalls")]
        [JsonProperty("function_call")]
        public Function Function { get; private set; }

        /// <summary>
        /// Optional, The name of the author of this message.<br/>
        /// May contain a-z, A-Z, 0-9, and underscores, with a maximum length of 64 characters.
        /// </summary>
        
        [JsonProperty("name")]
        public string Name { get; private set; }

        public override string ToString() { return Content != null ? Content.ToString() : string.Empty; }

        public static implicit operator string(Message message) { return message == null ? null : message.ToString(); }

        public bool ShouldSerializeName() { return Name != null; }
#pragma warning disable 0618 // Type or member is obsolete
        public bool ShouldSerializeFunction() { return Function != null; }
#pragma warning restore 0618 // Type or member is obsolete
        public bool ShouldSerializeToolCallId() { return ToolCallId != null; }
        public bool ShouldSerializeContent() { return true; }

        internal void CopyFrom(Delta other)
        {
            if (Role == 0 &&
                other != null && other.Role > 0)
            {
                Role = other.Role;
            }

            if (!string.IsNullOrEmpty(other == null ? null : other.Content))
            {
                Content += other.Content;
            }

            if (!string.IsNullOrWhiteSpace(other == null ? null : other.Name))
            {
                Name = other.Name;
            }

            if (other != null && other.ToolCalls != null)
            {
                toolCalls = toolCalls ?? new List<Tool>();

                foreach (var otherToolCall in other.ToolCalls)
                {
                    if (otherToolCall == null) { continue; }

                    if (otherToolCall.Index.HasValue)
                    {
                        if (otherToolCall.Index + 1 > toolCalls.Count)
                        {
                            toolCalls.Insert(otherToolCall.Index.Value, new Tool(otherToolCall));
                        }
                        
                        toolCalls[otherToolCall.Index.Value].CopyFrom(otherToolCall);
                    }
                    else
                    {
                        toolCalls.Add(new Tool(otherToolCall));
                    }
                }
            }

#pragma warning disable 0618 // Type or member is obsolete
            if (other != null && other.Function != null)
            {
                if (Function == null)
                {
                    Function = new Function(other.Function);
                }
                else
                {
                    Function.CopyFrom(other.Function);
                }
            }
#pragma warning restore 0618 // Type or member is obsolete
        }


    }
}
